package plgdb

import (
	"dgo/MyProj/PrjDBUtils"
	db_utils "dgo/goutils/db-utils"
	"fmt"
	"gitee.com/ymofen/supervalue"
)

/**
  "$update":{     // 更新, 删除, 添加 配置
     "table":"goods",    // 更新表名
     "keyfields":"id,name",    // 主键
     "ignoreinsertfields":"id;createtime",   // 添加时忽略字段 用分号分割
     "ignoreupdatefields":"id;updatetime",   // 更新时忽略字段 用分号分割
     "insertifempty":"fid;fxx",     // exupdate时才有效, 用分号分割 如果传入的更新记录中有任何一个值为空 则插入
     "insert":{"uptime":"$now$", "fuserid":"$userid$", "fid":"$newid$"},     // 添加时 字段赋值
     "update":{"uptime":"$now$"}      // 更新时 字段赋值
  }
*/

func (this *PlgDBBase) checkReadDBRes(param *PlgDBUpdateParam) (errcode int, err error) {

	dbres := param.DBResConf
	if dbres == nil {
		dbres = this.GetDBResConf(param.ResID)
		param.DBResConf = dbres
	}
	dbres = param.HttpReq.DoResConfig(dbres)
	if dbres == nil {
		errcode = ERR_IN_PARAM_INVALID
		err = fmt.Errorf("找不到对应的资源[%s]", param.ResID)
		return
	}

	if len(param.DataSourceid) == 0 {
		param.DataSourceid = this.Default_datasourceid
	}

	dbres.CheckStrFunc("__datasource", func(strv string) {
		param.DataSourceid = strv
	})

	if param.Dao == nil {
		dbname := param.DBName
		var dao *PrjDBUtils.DAOHelper
		if len(dbname) > 0 {
			dao = this.DoNewDAOHelper(param.DataSourceid, dbname, param)
		} else {
			dao = this.DoNewDAOHelper(param.DataSourceid, "", param)
		}
		param.Dao = dao

		err = dao.PrepareDBConn()
		if err != nil {
			errcode = ERR_DB_ERR
			return
		}
	}

	param.Dao.AfterUpdateFuncEx = func(uprec *PrjDBUtils.DaoUpdateRecord) {
		if uprec.Upcnt > 0 {
			if param.HttpReq.AfterUpdate != nil {
				param.HttpReq.AfterUpdate(param, uprec)
			}
			if this.OnAfterUpdateFunc != nil {
				this.OnAfterUpdateFunc(param, uprec.Data, uprec.Uptype)
			}
		}
	}

	upconf := dbres.ValueByName("$update")
	if upconf == nil {
		errcode = ERR_INNER
		err = fmt.Errorf("配置非法[%s],找不到对应的[$sel]配置", param.ResID)
		return
	}

	checkconf := upconf.ValueByName("check")
	if checkconf == nil {
		checkconf = dbres.ValueByName("check")
	}

	if ok, itm := this.checkVarByResConf(checkconf, param.GetParamVal); !ok {
		errcode = ERR_IN_PARAM_INVALID
		code := itm.IntByName("errcode", 0)
		msg := itm.StringByName("msg", "")
		if code != 0 {
			errcode = code
		}
		err = fmt.Errorf(msg)
		return
	}

	param.UpConf = upconf
	param.table = upconf.StringByName("table", "")
	param.keyfields = upconf.StringByName("keyfields", "")
	param.ignoreupdatefields = upconf.StringByName("ignoreupdatefields", "")
	param.ignoreinsertfields = upconf.StringByName("ignoreinsertfields", "")
	param.tracesql = upconf.IntByName("__tracesql", 0)
	param.trans = upconf.BoolByName("trans", false)

	param.Dao.DBConn.OnAfterExecuteSQLFunc = func(sql string, err error, args ...interface{}) {
		param.HttpReq.OnAfterExecSQL(param.tracesql, sql, err, args...)
	}
	return
}

func (this *PlgDBBase) DBResUpdateOne(param *PlgDBUpdateParam) (errcode int, err error) {
	errcode, err = this.checkReadDBRes(param)
	if errcode != 0 {
		return
	}

	dao := param.Dao
	dao.Updatetable = param.table
	dao.Keyfields = param.keyfields
	if len(dao.Keyfields) == 0 {
		return ERR_IN_PARAM_INVALID, fmt.Errorf("缺少指定更新主键!!!")
	}

	data := param.Data

	data.RemoveFields(param.ignoreupdatefields)

	if param.UpConf != nil { // 默认更新数据
		ex := param.UpConf.ValueByName("update")
		if ex != nil {
			ex.Range(func(key string, val *wrapper.SuperValue) bool {
				if !data.Exists(key) {
					if val.IsString() {
						str := val.String()
						this.checkProcessVar(&str, param.GetParamVal)
						data.SetKeyValue(key, str)
					} else {
						data.SetKeyValue(key, val)
					}

				}
				return true
			})
		}
	}
	if data.IfOneOfFieldsIsEmpty(dao.Keyfields) {
		return ERR_IN_PARAM_INVALID, fmt.Errorf("更新参数不完整:缺少更新主键对应的值!")
	}

	if param.trans {
		dao.DBConn.BeginTrans()
		defer dao.DBConn.AutoDoneTrans()
	}

	if param.Resp == nil {
		param.Resp = wrapper.NewSVObject()
	}

	if !this.innerBeforeUpdate(param) {
		return
	}

	upcnt, _, e1 := dao.UpdateEx(data, "", nil, nil)
	if e1 != nil {
		return ERR_DB_ERR, e1
	}
	param.Resp.SetKeyValue("upcnt", upcnt)

	return
}

func (this *PlgDBBase) innerBeforeUpdate(param *PlgDBUpdateParam) bool {
	if param.HttpReq.BeforeUpdate != nil {
		if !param.HttpReq.BeforeUpdate(param) {
			return false
		}
	}

	if this.OnBeforeUpdateRequestFunc != nil {
		this.OnBeforeUpdateRequestFunc(param)
	}
	return true
}

func (this *PlgDBBase) DBResExUpdateOne(param *PlgDBUpdateParam) (errcode int, err error) {
	errcode, err = this.checkReadDBRes(param)
	if errcode != 0 {
		return
	}

	dao := param.Dao
	dao.Updatetable = param.table
	dao.Keyfields = param.keyfields
	if len(dao.Keyfields) == 0 {
		return ERR_IN_PARAM_INVALID, fmt.Errorf("缺少指定更新主键!!!")
	}

	data := param.Data

	if param.trans {
		dao.DBConn.BeginTrans()
		defer dao.DBConn.AutoDoneTrans()
	}

	if param.Resp == nil {
		param.Resp = wrapper.NewSVObject()
	}

	if !this.innerBeforeUpdate(param) {
		return
	}

	upcnt, _, e1 := dao.InsertOrUpdateEx(data, func(db *db_utils.DBConn, action int, recUp *db_utils.RecUpdateUpbuilder) bool {
		var valkey string
		if action == db_utils.ACTION_APPEND {
			data.RemoveFields(param.ignoreinsertfields)
			valkey = "insert"
		} else {
			data.RemoveFields(param.ignoreupdatefields)
			valkey = "update"
		}
		if param.UpConf != nil { // 默认更新数据
			ex := param.UpConf.ValueByName(valkey)
			if ex != nil {
				ex.Range(func(key string, val *wrapper.SuperValue) bool {
					if !data.Exists(key) {
						if val.IsString() {
							str := val.String()
							this.checkProcessVar(&str, param.GetParamVal)
							data.SetKeyValue(key, str)
							recUp.SetValue(key, str)
						} else {
							data.SetKeyValue(key, val)
							recUp.SetValue(key, val.Variant())
						}

					}
					return true
				})
			}
		}
		if action == db_utils.ACTION_UPDATE {
			if data.IfOneOfFieldsIsEmpty(dao.Keyfields) {
				errcode = ERR_IN_PARAM_INVALID
				err = fmt.Errorf("更新参数不完整:缺少更新主键对应的值!")
				return false
			}
		}
		return true
	})
	if e1 != nil {
		return ERR_DB_ERR, e1
	}
	param.Resp.SetKeyValue("upcnt", upcnt)

	return
}

func (this *PlgDBBase) DBResInsertOne(param *PlgDBUpdateParam) (errcode int, err error) {
	errcode, err = this.checkReadDBRes(param)
	if errcode != 0 {
		return
	}

	dao := param.Dao
	data := param.Data

	// 删除
	data.RemoveFields(param.ignoreinsertfields)

	if param.UpConf != nil { // 默认插入
		ex := param.UpConf.ValueByName("insert")
		if ex != nil {
			ex.Range(func(key string, val *wrapper.SuperValue) bool {
				if val.IsString() {
					str := val.String()
					this.checkProcessVar(&str, param.GetParamVal)
					data.SetKeyValue(key, str)
				} else {
					data.SetKeyValue(key, val)
				}
				return true
			})
		}
	}

	if param.trans {
		dao.DBConn.BeginTrans()
		defer dao.DBConn.AutoDoneTrans()
	}

	if param.Resp == nil {
		param.Resp = wrapper.NewSVObject()
	}

	if !this.innerBeforeUpdate(param) {
		return
	}

	upcnt, _, e1 := dao.InsertEx2(data, param.table, "", nil, nil)
	if e1 != nil {
		return ERR_DB_ERR, e1
	}

	param.Resp.SetKeyValue("upcnt", upcnt)
	return
}

/*
*

	根据主键删除
*/
func (this *PlgDBBase) DBResDelOne(param *PlgDBUpdateParam) (errcode int, err error) {
	errcode, err = this.checkReadDBRes(param)
	if errcode != 0 {
		return
	}

	dao := param.Dao
	dao.Updatetable = param.table
	dao.Keyfields = param.keyfields
	if len(dao.Keyfields) == 0 {
		return ERR_IN_PARAM_INVALID, fmt.Errorf("缺少指定更新主键!!!")
	}

	data := param.Data

	if data.IfOneOfFieldsIsEmpty(dao.Keyfields) {
		return ERR_IN_PARAM_INVALID, fmt.Errorf("更新参数不完整:缺少更新主键对应的值!")
	}

	if param.trans {
		dao.DBConn.BeginTrans()
		defer dao.DBConn.AutoDoneTrans()
	}

	if param.Resp == nil {
		param.Resp = wrapper.NewSVObject()
	}

	if !this.innerBeforeUpdate(param) {
		return
	}

	upcnt, _, e1 := dao.Delete(data, dao.Keyfields, nil)
	if e1 != nil {
		return ERR_DB_ERR, e1
	}

	param.Resp.SetKeyValue("upcnt", upcnt)
	return
}

func (this *PlgDBBase) DBResBatchUpdate(param *PlgDBUpdateParam) (errcode int, err error) {
	errcode, err = this.checkReadDBRes(param)
	if errcode != 0 {
		return
	}

	dao := param.Dao
	dao.Updatetable = param.table
	dao.Keyfields = param.keyfields
	if len(dao.Keyfields) == 0 {
		return ERR_IN_PARAM_INVALID, fmt.Errorf("缺少指定更新主键!!!")
	}

	data := param.Data

	if param.trans {
		dao.DBConn.BeginTrans()
		defer dao.DBConn.AutoDoneTrans()
	}

	if param.Resp == nil {
		param.Resp = wrapper.NewSVObject()
	}

	this.innerBeforeUpdate(param)

	upcnt, _, e1 := dao.BatchUpdate(data, param.table, param.keyfields, "", "", 0,
		func(rec *db_utils.RecUpdateUpbuilder, action int, row *wrapper.SuperValue) bool {
			var valkey string
			if action == db_utils.ACTION_APPEND {
				rec.RemoveFields(param.ignoreinsertfields)
				valkey = "insert"
			} else {
				rec.RemoveFields(param.ignoreupdatefields)
				valkey = "update"
			}
			if param.UpConf != nil { // 默认更新数据
				ex := param.UpConf.ValueByName(valkey)
				if ex != nil {
					ex.Range(func(key string, val *wrapper.SuperValue) bool {
						if !rec.Exists(key) {
							if val.IsString() {
								str := val.String()
								this.checkProcessVar(&str, param.GetParamVal)
								rec.SetValue(key, str)
							} else {
								rec.SetValue(key, val)
							}
						}
						return true
					})
				}
			}
			if action == db_utils.ACTION_UPDATE {
				if row.IfOneOfFieldsIsEmpty(dao.Keyfields) {
					return false
				}
			}
			return true
		})

	if e1 != nil {
		return ERR_DB_ERR, e1
	}
	param.Resp.SetKeyValue("upcnt", upcnt)

	return
}
